#!/bin/ash

# hostsupdate will download lists of domains from various sources
# and convert them to a format suitable for an /etc/hosts file
# ultimately overwriting said file.
# if you want to keep your hosts file's header intact, create /etc/hosts.head
# which will be prepended to the resulting hosts file
# otherwise a sane default version will be used.

for dep in wc tr tar find grep sed sort curl rmdir mkdir; do
	type $dep >/dev/null || { echo "Dependency $dep is not in PATH"; exit 1; }
done

# forced update
[ "$1" = forced ] && echo "Forced update!" && rm -f lastfetch

####################################################
# Most variables used in the script are defined here
e="/usr/share/hosts-block/hosts-block-env.sh"
[ -r "$e" ] && . "$e" || { echo "Could not source environment. Quit."; exit 1; }
####################################################

[ -w "$hosts" ] || exit_err "The executing user $USER cannot write to $hosts"

# Create hosts.head with sane defaults, if it doesn't exist already
[ -r "$hostshead" ] || { cat << EOF > "$hostshead"
127.0.0.1 localhost.localdomain localhost
::1 localhost6.localdomain6 localhost6 ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
EOF
}

[ -d "$datadir/tmp" ] || mkdir -p "$datadir/tmp"
#######################################
cd "$datadir" || exit_err cd "$datadir"
#######################################

exit_cleanup() {
    rmdir -- "$datadir/lockdir"
	[ "$debug" = "1" ] || rm -rf "$datadir"/tmp/*
}
trap exit_cleanup EXIT INT TERM KILL

# to make sure only one instance is running use a lock directory
c=0
# https://unix.stackexchange.com/a/48510
while ! mkdir -- "$datadir/lockdir"; do
    sleep 1
    c=$((c+1))
    [ "$c" -ge "$timeout" ] && exit 1
done

# compare with final result; do not notify if hosts has not changed
oldchecksum="$(md5sum "$hosts")"

bail() {
    if [ $# -gt 0 ]; then
        echo "$@"
        [ "$bail" = "1" ] && notify "$@"
    fi
    [ "$bail" = "1" ] && exit_err "$@"
}

clean() {
    # $1 file to be cleaned
    [ -r "$1" ] || return
    sedscript='/^#.*/d
    s/^127\.0\.0\.1[[:space:]]*//g
    s/0\.0\.0\.0[[:space:]]*//g
    s/::1[[:space:]]*//g
    /^0\.0\.0\.0[[:space:]]*$/d
    /^127\.0\.0\.1[[:space:]]*$/d
    /^localhost[[:space:]]*$/d
    /^local[[:space:]]*$/d
    /^localhost.localdomain[[:space:]]*$/d
    /^localhost6[[:space:]]*$/d
    /^Malvertising list/d
    /!/d
    /:/d
    /%/d
    /&/d
    /\./!d
    /^malware-check.disconnect.me/d
    s/#.*//g
    s/\^.*//g
    s/\^//g
    s/|*//g
    s/|//g
    s/\[\.\]/./g
    s/\/\///g
    s/\/.*//g
    s/[[:space:]]*//g
    /^$/d'
    sed "$sedscript" "$1" | tr [:upper:] [:lower:]
}

if [ ! -r lastfetch ] || [ ! -r domains ] || [ $(( $(date '+%s') - $(cat lastfetch) )) -gt $(( interval * 60 * 60 * 24 )) ]; then
    #########################################
    #### Getting all the stuff ##############

    curlcmd="curl --silent --retry 10 --retry-connrefused --retry-delay 5 --location"

    rm -f tmp/*

    cd tmp || exit_err cd tmp

    # uassets (uBlock Origin) format needs massaging:
    echo "$uassets" | while read -r url; do
        [ -z "$url" ] && continue
        # check that it starts with http
        [ -n "${url%%http*}" ] && continue
        # Download & Extract what we need only
        dir='*u?ssets*'
        u_out="uassets_${uassets##*/}"
        if ${curlcmd} "$url" -o "$u_out"; then
            tar xzf "$u_out" "$dir/thirdparties/" "$dir/filters/" --exclude "$dir/thirdparties/*publicsuffix*"
            find $dir/ -type f -name '*\.md' -delete

            echo "uAssets: search for AdBlock formatted entries (hosts only)"
            regex='^\|\|[a-zA-Z0-9\-\.]*\^[[:space:]]*$'
            grep -rhE "$regex" $dir/ | tr -d '|^' >> list-uassets
            echo "uAssets: search for domain only entries, 1 per line"
            regex='^[[:space:]]*[a-zA-Z0-9][a-zA-Z0-9\-\.]*[a-zA-Z0-9][[:space:]]*$'
            grep -rhE "$regex" $dir/ >> list-uassets
            echo "uAssets: search for hosts file syntax entries"
            regex='^[[:space:]]*[0-9]\+\.0\.0\.[01][[:space:]]\+[a-zA-Z0-9][a-zA-Z0-9\-\.]*[a-zA-Z0-9][[:space:]]*$'
            grep -rhE "$regex" $dir/ | sed 's/^[[:space:]]*[0-9]\+\.0\.0\.[01][[:space:]]\+//g' >> list-uassets
        else
            bail "Fetching \"$url\" failed"
        fi
    done
    [ -r list-uassets ] && {
        echo "Removing unwanted stuff from uassets list"
        clean list-uassets > list-uassets.clean
    }

    # get lists of urls = metalist
    echo "$metalists" | while read -r url; do
        [ -n "${url%%http*}" ] && continue
        curl ${curlopts} "$url" || bail "Fetching \"$url\" failed"
    done >> metalist

    # add extra urls to the list
    echo "$listurls" | while read -r url; do
        [ -n "${url%%http*}" ] && continue
        echo "$url"
    done >> metalist

    [ -r metalist ] && {
        # get the actual lists from all urls
        while read -r url; do
        	[ "${url%%:*}" = http ] || [ "${url%%:*}" = https ] || continue
        	echo "Downloading $url"
        	curl ${curlopts} "$url" >>lists.all || bail "Fetching \"$url\" failed"
        done < metalist
    }

    [ -r lists.all ] && {
        echo "Removing unwanted stuff from lists.all"
        clean lists.all > lists.all.clean
    }

    cd .. || exit_err "cd .."

    lists=""
    for f in tmp/lists.all.clean tmp/list-uassets.clean; do [ -r $f ] && lists="$lists $f"; done
    [ -z "$lists" ] && { notify "After processing, there are no blocklists at all" "Quitting, old $hosts remains unchanged"; exit 1; }

    echo "Unique-sorting and merging all lists"
    sort -bfiuo domains $lists

    lines="$(wc -l domains)"
    lines="${lines%% *}"
    [ "$lines" -lt "$minlines" ] && { notify "New hosts file has fewer than $minlines lines" "Not overwriting $hosts"; exit 1; }

    # only now are we satisfied and create a new timestamp:
    date '+%s' > lastfetch

    ####
    #########################################
fi

# For black/whitelisting:
cp domains tmp/domains

# Removing whitelisted entries
[ -r "$whitelist" ] && {
    echo "$whitelist exists"
    while read -r line; do
        line="${line#*://}"
        line="${line%%/*}"
        [ -z "$line" ] && echo "Empty line" && continue
        grep -q "^$(echo "$line" | sed 's/\./\\./g')$" tmp/domains || { echo "$line is already not in hosts!"; continue; }
        echo "Removing $line from $hosts"
        sed -i "/^$(echo "$line" | sed 's/\./\\./g')$/d" tmp/domains
    done < "$whitelist"
    }

# Adding blacklisted entries
[ -r "$blacklist" ] && {
    echo "$blacklist exists"
    while read -r line; do
        line="${line#*://}"
        line="${line%%/*}"
        [ -z "$line" ] && echo "Empty line" && continue
        grep -q "^$(echo "$line" | sed 's/\./\\./g')$" tmp/domains && echo "$line is already in hosts!" && continue
        echo "Adding $line to $hosts"
        echo "$line" >> tmp/domains
    done < "$blacklist"
    }

cat "$hostshead" > "$hosts.new" || exit_err "initialise new hosts file with $hostshead"
sed "s/^/$prepend /g" tmp/domains > "$hosts.new" || exit_err "prepend $prepend"
mv  "$hosts.new" "$hosts" || exit_err "move end result into place"

newchecksum="$(md5sum "$hosts")"
echo "newchecksum: $newchecksum"
echo "oldchecksum: $oldchecksum"
if [ "$newchecksum" = "$oldchecksum" ]; then
    notify "Adblock Hosts updated" "But there was no change"
else
    notify -a \
    "restart;Restart org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager RestartUnit booster-browser@sailfish-browser.service replace" \
    "Adblock Hosts updated" "Click Restart to restart browser."
fi

exit 0
